#pragma once
#include <vector>
#include "semaphore.hpp"
#include"basic_buf.hpp"

// 缓冲区本身需要维护线程安全
template<typename T>
class basic_buf;

#define CIRCULAR_QUE_SZ 10

/*
    循环队列有两种设计方案：
    head == tail 表示空
    1. 使用计数器判断是否满
    2. 少用一个空间,当 tail + 1 = head时为满

    生产者使用head指针
    消费者使用tail指针
    这里使用第一种方案，用信号量来计数！！！！

    信号量是一把资源的计数器，它的本质工作就是把对资源就绪的情况由临界区内转到了临界区外。
    只要我们PV操作成功，那么我们一定存在对应的行为一定是合法

    存在多少种资源？2种资源 --》需要2个信号量
    信号量1 -- 空间资源
    信号量2 -- 数据资源！
*/

// 信号量只维护了生产者与消费者之间的同步互斥关系！
// 但是没有维护生产者和生产者，消费者和消费者之间的互斥关系！！！

template<typename T>
class CircularQueue : public basic_buf<T>
{
public:
    //声明使用基类的成员变量
    using basic_buf<T>::_mutex_pro;
    using basic_buf<T>::_mutex_con;

    using ptr = std::shared_ptr<CircularQueue>;
    CircularQueue(int pshared = 0,int val = CIRCULAR_QUE_SZ)
    :_sem_room(pshared,val) // 刚开始时，空间资源为n个
    ,_sem_data(pshared,0) // 刚开始时，数据资源为0个
    ,_head(0)
    ,_tail(0)
    {
        _que.resize(CIRCULAR_QUE_SZ);
    }
    virtual void push(const T& val)
    {
        // 消耗一个空间资源
        _sem_room.P();
        LockGuard lk(&_mutex_pro);
        {
            _que[_head++] = val;
            _head %= _que.size();
        }
        // 产生一个数据资源
        _sem_data.V();
    }
    virtual void pop(T* val)
    {
        // 消耗一个数据资源
        _sem_data.P();
        LockGuard lk(&_mutex_con);
        {
            *val = _que[_tail++];
            _tail %= _que.size();
        }
        
        // 生产一个空间资源
        _sem_room.V();
    }

    virtual bool empty() 
    {
        ;
    }
    virtual bool full() 
    {
        ;
    }

    // 为双缓冲区设计的接口
    virtual void push(const T& val,size_t sz)
    {}
    virtual void pop(T* val,size_t sz) 
    {}
private:
    std::vector<T> _que;
    size_t _head;
    size_t _tail;
    // 生产者信号量 - 空间资源
    Semaphore _sem_room; 
    // 消费者信号量 - 数据资源
    Semaphore _sem_data;
};
